package com.itheima.behavior.service.impl;

import com.itheima.behavior.service.UserProfileService;
import com.itheima.model.behavior.pojos.ReadingStatistics;
import com.itheima.model.behavior.pojos.UserBehavior;
import com.itheima.model.behavior.pojos.UserProfile;
import com.itheima.model.behavior.vos.CategoryPreferenceVo;
import com.itheima.model.behavior.vos.UserProfileVo;
import com.itheima.model.book.pojos.Book;
import com.itheima.model.common.dtos.ResponseResult;
import com.itheima.utils.thread.MpThreadLocalUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.aggregation.Aggregation;
import org.springframework.data.mongodb.core.aggregation.AggregationResults;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.time.ZoneId;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 用户画像服务实现类
 */
@Service
@Slf4j
public class UserProfileServiceImpl implements UserProfileService {

    @Autowired
    private MongoTemplate mongoTemplate;

    /**
     * 获取当前登录用户画像
     */
    @Override
    public ResponseResult getMyProfile() {
        Integer userId = MpThreadLocalUtil.getUser().getId();
        return getUserProfile(userId);
    }

    /**
     * 获取指定用户画像
     */
    @Override
    public ResponseResult getUserProfile(Integer userId) {
        try {
            // 查询用户画像
            Query query = new Query(Criteria.where("userId").is(userId));
            UserProfile profile = mongoTemplate.findOne(query, UserProfile.class);
            
            if (profile == null) {
                // 如果没有画像，先生成一个
                updateUserProfile(userId);
                profile = mongoTemplate.findOne(query, UserProfile.class);
            }

            // 构建VO对象
            UserProfileVo vo = buildUserProfileVo(profile);
            
            return ResponseResult.okResult(vo);
            
        } catch (Exception e) {
            log.error("获取用户画像失败: userId={}", userId, e);
            return ResponseResult.errorResult(500, "获取用户画像失败");
        }
    }

    /**
     * 刷新当前登录用户画像
     */
    @Override
    public ResponseResult refreshMyProfile() {
        Integer userId = MpThreadLocalUtil.getUser().getId();
        return updateUserProfile(userId);
    }

    /**
     * 更新用户画像
     */
    @Override
    public ResponseResult updateUserProfile(Integer userId) {
        try {
            log.info("开始更新用户画像: userId={}", userId);
            
            // 1. 计算总阅读时长
            Integer totalReadingTime = calculateTotalReadingTime(userId);
            
            // 2. 计算阅读图书总数
            Integer totalBooksRead = calculateTotalBooksRead(userId);
            
            // 3. 计算活跃天数
            Integer activeDays = calculateActiveDays(userId);
            
            // 4. 计算最喜欢的分类
            String favoriteCategory = calculateFavoriteCategory(userId);
            
            // 5. 计算阅读等级
            String readingLevel = calculateReadingLevel(totalReadingTime);
            
            // 6. 获取偏好标签
            List<String> preferenceTags = calculatePreferenceTags(userId);
            
            // 7. 获取最后活跃时间
            Date lastActiveTime = getLastActiveTime(userId);
            
            // 8. 更新或创建用户画像
            Query query = new Query(Criteria.where("userId").is(userId));
            UserProfile profile = mongoTemplate.findOne(query, UserProfile.class);
            if (profile == null) {
                profile = new UserProfile();
                profile.setUserId(userId);
                profile.setCreateTime(new Date());
            }
            
            profile.setTotalReadingTime(totalReadingTime);
            profile.setTotalBooksRead(totalBooksRead);
            profile.setActiveDays(activeDays);
            profile.setFavoriteCategory(favoriteCategory);
            profile.setReadingLevel(readingLevel);
            profile.setPreferenceTags(preferenceTags);
            profile.setLastActiveTime(lastActiveTime);
            profile.setUpdateTime(new Date());
            
            mongoTemplate.save(profile);
            
            log.info("用户画像更新成功: userId={}, level={}, category={}", 
                    userId, readingLevel, favoriteCategory);
            
            return ResponseResult.okResult("用户画像更新成功");
            
        } catch (Exception e) {
            log.error("更新用户画像失败: userId={}", userId, e);
            return ResponseResult.errorResult(500, "更新用户画像失败");
        }
    }

    /**
     * 批量更新用户画像
     */
    @Override
    public ResponseResult batchUpdateUserProfiles() {
        try {
            log.info("开始批量更新用户画像");
            
            // 获取所有有行为记录的用户ID
            List<Integer> userIds = mongoTemplate.findDistinct(
                new Query(), "userId", UserBehavior.class, Integer.class);
            
            int successCount = 0;
            int failCount = 0;
            
            for (Integer userId : userIds) {
                try {
                    updateUserProfile(userId);
                    successCount++;
                } catch (Exception e) {
                    log.error("更新用户画像失败: userId={}", userId, e);
                    failCount++;
                }
            }
            
            log.info("批量更新用户画像完成: 成功={}, 失败={}", successCount, failCount);
            
            Map<String, Object> result = new HashMap<>();
            result.put("total", userIds.size());
            result.put("success", successCount);
            result.put("fail", failCount);
            
            return ResponseResult.okResult(result);
            
        } catch (Exception e) {
            log.error("批量更新用户画像失败", e);
            return ResponseResult.errorResult(500, "批量更新用户画像失败");
        }
    }

    /**
     * 计算用户阅读等级
     */
    @Override
    public String calculateReadingLevel(Integer totalReadingTime) {
        if (totalReadingTime == null || totalReadingTime < 60) {
            return "初出茅庐";
        } else if (totalReadingTime < 300) {
            return "崭露头角";
        } else if (totalReadingTime < 600) {
            return "渐入佳境";
        } else if (totalReadingTime < 1200) {
            return "炉火纯青";
        } else if (totalReadingTime < 2400) {
            return "登峰造极";
        } else {
            return "一代宗师";
        }
    }

    /**
     * 获取当前登录用户阅读偏好
     */
    @Override
    public ResponseResult getMyPreferences() {
        Integer userId = MpThreadLocalUtil.getUser().getId();
        return getUserPreferences(userId);
    }

    /**
     * 获取指定用户阅读偏好
     */
    @Override
    public ResponseResult getUserPreferences(Integer userId) {
        try {
            // 获取分类偏好
            List<CategoryPreferenceVo> categoryPreferences = getCategoryPreferences(userId);
            
            // 获取偏好标签
            List<String> preferenceTags = calculatePreferenceTags(userId);
            
            Map<String, Object> result = new HashMap<>();
            result.put("categoryPreferences", categoryPreferences);
            result.put("preferenceTags", preferenceTags);
            
            return ResponseResult.okResult(result);
            
        } catch (Exception e) {
            log.error("获取用户偏好失败: userId={}", userId, e);
            return ResponseResult.errorResult(500, "获取用户偏好失败");
        }
    }

    // ==================== 私有辅助方法 ====================

    /**
     * 计算总阅读时长（分钟）
     */
    private Integer calculateTotalReadingTime(Integer userId) {
        Query query = new Query(Criteria.where("userId").is(userId)
                .and("behaviorType").is("reading"));
        
        List<UserBehavior> behaviors = mongoTemplate.find(query, UserBehavior.class);
        
        int totalSeconds = behaviors.stream()
                .mapToInt(b -> b.getDuration() != null ? b.getDuration() : 0)
                .sum();
        
        return totalSeconds / 60; // 转换为分钟
    }

    /**
     * 计算阅读图书总数
     */
    private Integer calculateTotalBooksRead(Integer userId) {
        Query query = new Query(Criteria.where("userId").is(userId)
                .and("behaviorType").in("book_view", "reading")
                .and("targetType").is("book"));
        
        List<UserBehavior> behaviors = mongoTemplate.find(query, UserBehavior.class);
        
        // 去重统计图书数量
        return (int) behaviors.stream()
                .map(UserBehavior::getTargetId)
                .distinct()
                .count();
    }

    /**
     * 计算活跃天数
     */
    private Integer calculateActiveDays(Integer userId) {
        Query query = new Query(Criteria.where("userId").is(userId));
        List<UserBehavior> behaviors = mongoTemplate.find(query, UserBehavior.class);
        
        // 按日期去重
        return (int) behaviors.stream()
                .map(b -> {
                    if (b.getCreateTime() != null) {
                        return b.getCreateTime().toInstant()
                                .atZone(ZoneId.systemDefault())
                                .toLocalDate();
                    }
                    return null;
                })
                .filter(Objects::nonNull)
                .distinct()
                .count();
    }

    /**
     * 计算最喜欢的分类
     */
    private String calculateFavoriteCategory(Integer userId) {
        List<CategoryPreferenceVo> preferences = getCategoryPreferences(userId);
        
        if (preferences.isEmpty()) {
            return "暂无";
        }
        
        return preferences.get(0).getCategoryName();
    }

    /**
     * 获取分类偏好分布
     */
    private List<CategoryPreferenceVo> getCategoryPreferences(Integer userId) {
        // 这里需要关联图书表获取分类信息
        // 简化实现：从行为数据中统计
        Query query = new Query(Criteria.where("userId").is(userId)
                .and("targetType").is("book"));
        
        List<UserBehavior> behaviors = mongoTemplate.find(query, UserBehavior.class);
        
        // 统计各分类的阅读次数
        Map<String, Long> categoryCount = new HashMap<>();
        
        // 这里需要根据targetId查询图书信息获取分类
        // 暂时使用模拟数据
        categoryCount.put("文学", 10L);
        categoryCount.put("科技", 5L);
        categoryCount.put("历史", 3L);
        
        long total = categoryCount.values().stream().mapToLong(Long::longValue).sum();
        
        return categoryCount.entrySet().stream()
                .map(entry -> CategoryPreferenceVo.builder()
                        .categoryName(entry.getKey())
                        .bookCount(entry.getValue().intValue())
                        .percentage(total > 0 ? (entry.getValue() * 100.0 / total) : 0.0)
                        .build())
                .sorted((a, b) -> b.getBookCount().compareTo(a.getBookCount()))
                .collect(Collectors.toList());
    }

    /**
     * 计算偏好标签
     */
    private List<String> calculatePreferenceTags(Integer userId) {
        List<String> tags = new ArrayList<>();
        
        // 根据行为数据生成标签
        Integer totalReadingTime = calculateTotalReadingTime(userId);
        Integer activeDays = calculateActiveDays(userId);
        
        if (totalReadingTime > 600) {
            tags.add("资深读者");
        }
        if (activeDays > 30) {
            tags.add("坚持阅读");
        }
        
        // 添加分类相关标签
        String favoriteCategory = calculateFavoriteCategory(userId);
        if (favoriteCategory != null && !favoriteCategory.equals("暂无")) {
            tags.add(favoriteCategory + "爱好者");
        }
        
        return tags;
    }

    /**
     * 获取最后活跃时间
     */
    private Date getLastActiveTime(Integer userId) {
        Query query = new Query(Criteria.where("userId").is(userId))
                .with(org.springframework.data.domain.Sort.by(
                        org.springframework.data.domain.Sort.Direction.DESC, "createTime"))
                .limit(1);
        
        UserBehavior behavior = mongoTemplate.findOne(query, UserBehavior.class);
        
        return behavior != null ? behavior.getCreateTime() : new Date();
    }

    /**
     * 构建用户画像VO对象
     */
    private UserProfileVo buildUserProfileVo(UserProfile profile) {
        if (profile == null) {
            return null;
        }
        
        return UserProfileVo.builder()
                .userId(profile.getUserId())
                .totalReadingTime(profile.getTotalReadingTime())
                .totalBooksRead(profile.getTotalBooksRead())
                .activeDays(profile.getActiveDays())
                .readingLevel(profile.getReadingLevel())
                .levelDesc(getLevelDesc(profile.getReadingLevel()))
                .nextLevelTime(getNextLevelTime(profile.getTotalReadingTime()))
                .favoriteCategory(profile.getFavoriteCategory())
                .categoryPreferences(getCategoryPreferences(profile.getUserId()))
                .preferenceTags(profile.getPreferenceTags())
                .build();
    }

    /**
     * 获取等级描述
     */
    private String getLevelDesc(String level) {
        Map<String, String> descMap = new HashMap<>();
        descMap.put("初出茅庐", "刚开始阅读之旅");
        descMap.put("崭露头角", "养成了阅读习惯");
        descMap.put("渐入佳境", "阅读能力不断提升");
        descMap.put("炉火纯青", "已是阅读达人");
        descMap.put("登峰造极", "阅读大师级别");
        descMap.put("一代宗师", "阅读领域的传奇");
        
        return descMap.getOrDefault(level, "");
    }

    /**
     * 计算距离下一等级所需时长
     */
    private Integer getNextLevelTime(Integer currentTime) {
        if (currentTime == null) currentTime = 0;
        
        if (currentTime < 60) return 60 - currentTime;
        if (currentTime < 300) return 300 - currentTime;
        if (currentTime < 600) return 600 - currentTime;
        if (currentTime < 1200) return 1200 - currentTime;
        if (currentTime < 2400) return 2400 - currentTime;
        
        return 0; // 已达到最高等级
    }
}

